package com.mls.fivedistrict.server.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mls.fivedistrict.common.PageFilter;
import com.mls.fivedistrict.common.ServiceResponse;
import com.mls.fivedistrict.dao.OrePoolMapper;
import com.mls.fivedistrict.dao.ProductPlanMapper;
import com.mls.fivedistrict.enums.RecordProductTypeEnum;
import com.mls.fivedistrict.enums.RecordStatusEnum;
import com.mls.fivedistrict.pojo.*;
import com.mls.fivedistrict.server.*;
import com.mls.fivedistrict.util.TimeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

import static java.math.BigDecimal.ROUND_DOWN;

/**
 * Created by chenxiuxiang on 2018/4/1.
 */
@Service("productPlanService")
public class ProductPlanServiceImpl implements ProductPlanService {
    @Resource(name = "productPlanMapper")
    ProductPlanMapper productPlanMapper;
    @Resource(name = "orePoolMapper")
    OrePoolMapper orePoolMapper;

    @Resource(name = "integralService")
    IntegralService integralService;
    @Autowired
    UserService userService;
    @Autowired
    PropertyService propertyService;
    @Autowired
    RecordService recordService;
    @Autowired
    ProductPlanService productPlanService;
    @Autowired
    LogService logService;

    @Override
    public int addProductPlan(ProductPlan productPlan) {
        return productPlanMapper.insertSelective(productPlan);
    }

    @Override
    public ServiceResponse editProductPlan(ProductPlan productPlan) {
        int i = productPlanMapper.updateByPrimaryKeySelective(productPlan);
        if (i > 0) {
            return ServiceResponse.createSuccessResponse();
        }
        return ServiceResponse.createErrorResponse();
    }

    @Override
    public ServiceResponse getProductPlan(PageFilter pageFilter) {
        ProductPlanExample productPlanExample = new ProductPlanExample();
        ProductPlanExample.Criteria criteria = productPlanExample.createCriteria();
        Optional.ofNullable(pageFilter.getFilterMap().get("poolId")).map(poolId -> criteria.andPoolIdEqualTo(Long.valueOf(poolId)));
        PageHelper.startPage(pageFilter.getPageNum(), pageFilter.getPageSize());
        List<ProductPlan> productPlans = productPlanMapper.selectByExample(productPlanExample);
        PageInfo pageInfo = new PageInfo(productPlans, 5);
        return ServiceResponse.createSuccessResponse(pageInfo);
    }

    @Override
    public ServiceResponse getProductPlanDetail(Long productPlanId) {
        ProductPlan productPlan = productPlanMapper.selectByPrimaryKey(productPlanId);
        if (productPlan != null) {
            return ServiceResponse.createSuccessResponse(productPlan);
        }
        return ServiceResponse.createErrorResponse();
    }

    @Override
    public List<ProductPlan> getProductPlanByTask() {
        ProductPlanExample productPlanExample = new ProductPlanExample();
        ProductPlanExample.Criteria criteria = productPlanExample.createCriteria();
        criteria.andDateLessThanOrEqualTo(TimeUtils.date2D(new Date()));
        criteria.andResidueGreaterThan(new BigDecimal(0));
        List<ProductPlan> productPlans = productPlanMapper.selectByExample(productPlanExample);
        return productPlans;
    }

    @Override
    public OrePool getPoolByProductId(Long productPlanId) {
        OrePool orePool = orePoolMapper.selectByProductId(productPlanId);
        return orePool;
    }

    @Override
    public ProductPlan getProductPlanById(Long productPlanId) {
        ProductPlan productPlan = productPlanMapper.selectByPrimaryKey(productPlanId);
        return productPlan;
    }

    @Transactional
    @Override
    public void produceIntegral() {
        //获取产出计划列表
        List<ProductPlan> productPlans = productPlanService.getProductPlanByTask();
        for (ProductPlan productPlan : productPlans) {
            //上次产出时间
            Date lastOutputDate = productPlan.getLastProductTime();
            if (lastOutputDate == null) {
                productIntegral(productPlan, 0, 0);
            } else {
                //产出频率
                Long frequencyId = productPlan.getFrequency();
                //当前时间
                Date nowDate = new Date();
                //判断是否是今天 不是今天用当天的24点 减去还剩多少次
                int value;
                if (!TimeUtils.isToday(lastOutputDate.getTime())) {
                    long lastTime = TimeUtils.date24(lastOutputDate);
                    value = (int) (((lastTime - lastOutputDate.getTime()) / 1000 / 60) / Long.valueOf(frequencyId));

                } else {
                    value = (int) (((nowDate.getTime() - lastOutputDate.getTime()) / 1000 / 60) / Long.valueOf(frequencyId));
                }
                if (value >= 1) {
                    for (int i = 0; i < value; i++) {
                        //根据差值判断执行几次积分产出
                        productIntegral(productPlan, i, value);
                    }
                }

            }

        }
    }

    private void productIntegral(ProductPlan productPlan, int index, int total) {

        //积分最小算力
        Map<String, String> filterMap = new HashMap<>();
        if (productPlan.getIntegral() == null) {
            return;
        }
        filterMap.put("calculate", String.valueOf(productPlan.getIntegral().getMinParticipationCalculate()));
        filterMap.put("isDelete", "false");
        filterMap.put("isEnable", "true");
        if (total > 1 && index != total - 1) {
            //代表中间服务器宕机 之后创建的用户不参与分
            filterMap.put("startDate", (productPlan.getLastProductTime().getTime() + productPlan.getFrequency() * 60 * 1000) + "");
        }
        List<User> userList = userService.getUserListForTask(filterMap);
        if (userList.size() <= 0) {
            return;
        }
        double calculateSum = (double) userService.calculateSum(productPlan.getIntegral().getMinParticipationCalculate()).getData();
        if (calculateSum <= 0) {
            return;
        }
        BigDecimal residueTotal = productPlan.getTotal();
        int totalZero = residueTotal.compareTo(BigDecimal.ZERO);
        //剩余总量
        if (totalZero <= 0) {
            return;
        }
        //剩余多少积分
        BigDecimal residue = productPlan.getResidue();
        int zero = residue.compareTo(BigDecimal.ZERO);
        if (zero <= 0) {
            return;
        }
        //上次产出时间
        Date lastOutputDate = productPlan.getLastProductTime();
        if (lastOutputDate == null) {
            lastOutputDate = new Date();
        }
        //产出时间距离24:00还剩多少毫秒
        long nowMistiming = TimeUtils.date24Time(lastOutputDate);
        long minuteMistiming = nowMistiming / 1000 / 60;
        //总频率
        long totalFrequency = (minuteMistiming / productPlan.getFrequency());
        if (totalFrequency == 0) {
            return;
        }
        //每次频率应该分多少积分
        BigDecimal onceIntegral = residue.divide(new BigDecimal(totalFrequency), 8, ROUND_DOWN);
        //每个算力应该分多少份
        BigDecimal onceByCalculateIntegral = onceIntegral.divide(new BigDecimal(calculateSum), 8, ROUND_DOWN);

        List<Record> records = new ArrayList<>();

        //将每个人应该获得的积分写入
        for (User user : userList) {
            Record record = new Record();
            Integer calculate = user.getCalculate();
            BigDecimal userIntegral;
            userIntegral = onceByCalculateIntegral.multiply(new BigDecimal(calculate)).setScale(8, ROUND_DOWN);
            record.setValue(userIntegral);
            record.setStatus(RecordStatusEnum.WAITRECEIVE.getValue());
            record.setIntergralId(productPlan.getIntegtalId());
            record.setSource(RecordProductTypeEnum.MINING.getValue());
            record.setUserId(user.getId());
            record.setOrePoolId(productPlan.getPoolId());
            //添加记录
            records.add(record);
        }
        if (records.size() <= 0) {
            return;
        }
        //每10000条执行一次进行插入
        //总共执行多少次
        int totlaSplice = 10000;
        int times = (int) Math.ceil(records.size() * 1.0 / totlaSplice);
        if (times > 1) {
            for (int i = 0; i < times; i++) {
                List<Record> timeRecords = new ArrayList<>();
                int sum = records.size();
                if ((i + 1) * totlaSplice < records.size()) {
                    sum = (i + 1) * totlaSplice;
                }
                for (int t = i * totlaSplice; t < sum; t++) {
                    timeRecords.add(records.get(t));
                }
                recordService.insertBash(timeRecords);
            }
        } else {
            recordService.insertBash(records);
        }

//        int totlaSplice = 10 * 10000;
//        int times = (int) Math.ceil(records.size() / totlaSplice);
//        if (times > 1) {
//            for (int i = 0; i < times; i++) {
//                List<Record> timeRecords = new ArrayList<>();
//                for (int t = i * totlaSplice; t < (i + 1) * totlaSplice; t++) {
//                    timeRecords.add(records.get(i));
//                }
//                recordService.insertBash(timeRecords);
//            }
//        } else {
//            recordService.insertBash(records);
//        }
        //更新上次产出时间和剩余天数和剩余积分
        BigDecimal surplusIntegral = residue.subtract(onceIntegral).setScale(8, ROUND_DOWN);//剩余积分
        ProductPlan newProductPlan = new ProductPlan();
        newProductPlan.setLastProductTime(new Date());
        newProductPlan.setResidue(surplusIntegral);
        newProductPlan.setId(productPlan.getId());
        productPlanService.editProductPlan(newProductPlan);
        productPlan.setResidue(surplusIntegral);
        productPlan.setLastProductTime(TimeUtils.millis2Date(lastOutputDate.getTime() + productPlan.getFrequency() * 60 * 1000));
        //更新使用积分
        Integral integralDetail = integralService.getIntegralDetail(productPlan.getIntegtalId());
        Integral integral = new Integral();
        integral.setId(integralDetail.getId());
        integral.setUserIntegral(integralDetail.getUserIntegral().add(onceIntegral).setScale(8, ROUND_DOWN));
        integralService.editIntegral(integral);

        //添加产出日志
        ProductLog productLog = new ProductLog();
        productLog.setFrequency(Math.toIntExact(productPlan.getFrequency()));
        productLog.setPeopleTotal(userList.size());
        productLog.setPoolId(productPlan.getPoolId());
        productLog.setProductTotal(onceIntegral);
        productLog.setSumCalculate((long) calculateSum);
        productLog.setIntegralId(productPlan.getIntegtalId());
        productLog.setResidue(surplusIntegral);
        productLog.setProductPlanId(productPlan.getId());
        if (productPlan.getIntegral() != null) {
            productLog.setIntegralName(productPlan.getIntegral().getName());
        }
        logService.addProductLog(productLog);

    }
}
